package com.wn.course.view

import android.animation.ObjectAnimator
import android.view.View
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.paging.LoadState
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.wn.common.base.BaseFragment
import com.wn.common.net.config.EYE_NAME
import com.wn.common.net.config.EYE_VALUE
import com.wn.course.CourseViewModel
import com.wn.course.R
import com.wn.course.databinding.FragmentCourseBinding
import com.wn.course.repository.data.CourseCategory
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import libcore.net.okhttp.OkDomain
import javax.inject.Inject

/**
 * @Author: wn
 * @Date: 2023/8/8 16:54
 * @Description: 课程中心模块
 */
@AndroidEntryPoint
class CourseFragment : BaseFragment<FragmentCourseBinding>() {

  override fun getLayoutRes() = R.layout.fragment_course

  private val viewModel by viewModels<CourseViewModel>()

  @Inject
  lateinit var adapter: CourseAdapter

  @Inject
  lateinit var footerAdapter: CourseFooterAdapter

  override fun initView() {
    super.initView()
    mBinding.apply {
      vm = viewModel
      /**
       * tabLayout点击事件
       * 打开的时候会点击一次
       */
      tlCategoryCourse.addOnTabSelectedListener(object : OnTabSelectedListener {
        // tab被点击的时候回调 进入界面触发 all
        override fun onTabSelected(tab: TabLayout.Tab?) {
          viewModel.apply {
            // 获取 CourseType
            val courseTypeList = liveCourseType.value
            // 拿到点击的tab的position
            val index = tab?.position ?: 0
            // 1 view上直接追加了 0--all , view中的 1 对应 liveCourseType中的 0
            /* type = if (index > 0) courseTypeList?.get(index - 1)?.code ?: "all" else "all"*/
            // 2 数据驱动 视图 observe 中 已经  对 list  进行了  add(0)  所以 这里是 一一对应的
            mainType = courseTypeList?.get(index)?.code ?: "全部"
            // 刷新
            refreshDataAtActivity()
          }
        }

        // tab未被点击时回调
        override fun onTabUnselected(tab: TabLayout.Tab?) {
        }

        // tab重新点击时回调
        override fun onTabReselected(tab: TabLayout.Tab?) {
        }
      })
      // paging3
      // 上拉加载 --> 添加  底部 加载进度条  和 加载失败 重新加载按钮   (范围--加载中)
      rvCourse.adapter = adapter.withLoadStateFooter(footerAdapter)

      // 下拉刷新-- Repository中 每次都需要 不同的 PagingSource 实例  那里无需 hilt
      adapter.apply {
        // 进度条颜色  背景色 setProgressBackgroundColorSchemeResource
        swipeRefresh.setColorSchemeResources(com.wn.common.R.color.colorPrimary)
        // 开启下拉刷新监听
        swipeRefresh.setOnRefreshListener {
          refresh()
        }
        // 下拉刷新 进度条取消
        lifecycleScope.launchWhenCreated {
          loadStateFlow.collectLatest {
            swipeRefresh.isRefreshing = it.refresh is LoadState.Loading
          }
        }

        // 初始化 加载状态监听器  -- (函数作用范围--初始化)
        addLoadStateListener {
          when (it.refresh) {
            is LoadState.NotLoading -> {
              loadErrorView?.isVisible = it.append.endOfPaginationReached && itemCount < 1
              rvCourse.visibility = View.VISIBLE
            }
            // 这里添加一个  没有数据前的空白页
            is LoadState.Loading -> {
              rvCourse.visibility = View.INVISIBLE
            }
            is LoadState.Error -> {
              val state = it.refresh as LoadState.Error
              // 这里添加一个  错误页面 点击 Retry  初始化生效
              showLoadErrorView("Load Error: ${state.error.message}") {
                adapter.retry()
              }
            }
          }
        }
      }
    }
  }

  override fun initData() {
    super.initData()
    viewModel.apply {
      // liveData 控制 text end 图标翻转
      typePopupOb.observeKt {
        val icon = mBinding.spinnerTypeCourseIcon
        if (it == false) {
          // 创建一个动画来旋转图像180度
          val rotateAnimation = ObjectAnimator.ofFloat(icon, "rotation", 0f, 180f)
          // 设置动画的持续时间
          rotateAnimation.duration = 200
          // 开始动画
          rotateAnimation.start()
        } else {
          val rotateAnimation = ObjectAnimator.ofFloat(icon, "rotation", 180f, 0f)
          rotateAnimation.duration = 200
          rotateAnimation.start()
        }
      }

      // 动态设置 TabLayout
      liveCourseType.observeKt {
        // 清除所有的 tabItem 因为返回的数据没有"全部"，要添加上，以防刷新丢掉了"全部"
        mBinding.apply {
          tlCategoryCourse.removeAllTabs()
          it?.apply {
            // ArrayList 前方添加数据
            add(
              0, CourseCategory.CourseCategoryItem(
                "全部",
                0,
                "全部"
              )
            )
            // 遍历生成 tabItem
            forEach { item ->
              tlCategoryCourse.addTab(
                tlCategoryCourse.newTab().also { tab ->
                  tab.text = item.title
                }
              )
            }
          }
        }
      }

      // 更改筛选条件 -- 数据驱动 -- 刷新
      refreshLive.observeKt {
        refreshDataAtActivity()
      }
    }
  }

  override fun initConfig() {
    super.initConfig()
    viewModel.apply {
      /**
       * 初始化 加载 需要动态切换的 BaseUrl
       * 添加 github 域名
       * 关闭  Log
       */
      OkDomain.setDomain(EYE_NAME, EYE_VALUE)
      OkDomain.debug = false

      // 获取 tab 分类
      getCourseCategory()
      // 配置 popup
      configPopFilter(mBinding)
    }
  }

  // Activity 中请求 刷新 数据
  private fun refreshDataAtActivity() {
    // 获取课程列表 paging3
    lifecycleScope.launchWhenCreated {
      viewModel.fetchData()
        .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
        .collect { data ->
          adapter.submitData(data)
        }
    }
  }

  private var loadErrorView: View? = null

  /**
   * 初始化加载失败时 通过此方法显示提示界面给用户。
   * @param tip 界面中的提示信息
   * @param block 点击屏幕重新加载，回调处理。
   */
  private fun showLoadErrorView(tip: String, block: View.() -> Unit) {
    mBinding.apply {
      if (loadErrorView != null) {
        loadErrorView?.isVisible = true
      } else {
        val viewStub = stubErrorViewCourse.loadErrorViewCourse
        loadErrorView = viewStub.inflate()
      }
      val loadErrorText = loadErrorView?.findViewById<AppCompatTextView>(R.id.loadErrorText)
      loadErrorText?.text = tip
      loadErrorView?.setOnClickListener(block)
    }
  }
}